package com.example.service.impl;

import cn.hutool.core.lang.TypeReference;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.json.JSONUtil;
import cn.hutool.log.Log;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.bean.Menu;
import com.example.bean.RoleMenu;
import com.example.bean.User;
import com.example.common.RedisCode;
import com.example.exception.ServiceException;
import com.example.mapper.MenuMapper;
import com.example.mapper.RoleMapper;
import com.example.mapper.RoleMenuMapper;
import com.example.service.MenuService;
import com.example.until.*;
import com.example.service.UserService;
import com.example.mapper.UserMapper;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.mail.MailException;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * @author wjf
 * @description 针对表【sys_user】的数据库操作Service实现
 * @createDate 2022-09-19 19:04:13
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
    private static final Log LOG = Log.get();
    /**
     * 前端传user对象数据，在数据中查
     *
     * @param userDto
     * @return
     */
    @Resource
    private UserMapper userMapper;

    @Resource
    private RoleMapper roleMapper;

    @Resource
    private MenuService MenuService;

    @Resource
    private RoleMenuMapper roleMenuMapper;

    @Value("${spring.mail.username}")
    private String from;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;


    @Resource
    private JavaMailSender javaMailSender;

    public User getUserInfo(UserDto userDto) {
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("username", userDto.getUsername())
                .eq("password", userDto.getPassword());

        User one;
        try {
            one = getOne(queryWrapper);
            return one;
        } catch (Exception e) {
            LOG.error(e);
            throw new ServiceException(ResultCodeEnum.SERVICE_ERROR); //抛出服务器异常
        }
    }

    @Override
    public UserDto login(UserDto userDto) {
        User one = getUserInfo(userDto);
        if (one != null) {
            BeanUtils.copyProperties(one, userDto);
            //设置token
            String token = TokenUtils.genToken(one.getId().toString(), one.getPassword());
            userDto.setToken(token);

            String roleName = one.getRole();
            //设置用户的菜单列表
            List<Menu> roleMenus = getRoleMenu(roleName);
            userDto.setMenus(roleMenus);

            return userDto;
        } else {
            throw new ServiceException(ResultCodeEnum.DATA_ERROR);
        }
    }

    @Override
    public User register(UserDto userDto) {
        User one = getUserInfo(userDto);
        if (one == null) {
            one = new User();
            BeanUtils.copyProperties(userDto, one);
            save(one);
        } else {
            throw new ServiceException(ResultCodeEnum.USER_EXCEPTION);  //用户存在
        }
        return one;
    }

    @Override
    @Transactional
    public Result select(UserUpdate userUpdate) {
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("username", userUpdate.getUsername())
                .eq("password", userUpdate.getOldPassword());
        User user;
        try {
            user = userMapper.selectOne(queryWrapper);
        } catch (Exception e) {
            LOG.error(e);
            throw new ServiceException(ResultCodeEnum.SERVICE_ERROR);
        }

        if (user != null) {
            return Result.ok();
        } else {
            return Result.fail().message("密码错误");
        }
    }

    @Override
    public Integer update(UserUpdate userUpdate) {
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("username", userUpdate.getUsername())
                .eq(StringUtils.isNotBlank(userUpdate.getNewPassword()), "password", userUpdate.getNewPassword());
        int i;
        try {
            i = userMapper.updatePassword(userUpdate);
        } catch (Exception e) {
            throw new ServiceException(ResultCodeEnum.SERVICE_ERROR);
        }

        return i;

    }

    /**
     * 发送验证码
     * @param email
     * @param type
     */
    @Override
    public void sendEmail(String email, Integer type) {
        SimpleMailMessage message = new SimpleMailMessage();
        String code = RandomUtil.randomNumbers(4);
        message.setFrom(from);
        message.setTo(email);
        if (type==1){
            message.setSubject("登录邮箱验证");
            message.setText("您本次登录的验证码是: " + code + ",有效期5分钟。请妥善保管,切勿泄露 ");
        }
        if (type==2){
            message.setSubject("重置密码验证");
            message.setText("您本次重置密码的验证码是: " + code + ",有效期5分钟。请妥善保管,切勿泄露 ");
        }
        javaMailSender.send(message);
        UserEmail user = new UserEmail();
        user.setEmail(email);
        user.setCode(code);
        stringRedisTemplate.opsForValue().set(email, JSONUtil.toJsonStr(user),300, TimeUnit.SECONDS);   //以邮箱账号为key 把code存入redis
    }

    /**
     * 通过邮箱和验证码完成登录
     * @param email
     * @param code
     * @return
     */
    @Override
    public UserDto loginEmail(String email, String code) {
        String jsonStr = stringRedisTemplate.opsForValue().get(email);//从缓存中获得code
        if (jsonStr==null){
            throw new RuntimeException("验证码失效,请重新发送");
        }
        UserEmail user = JSONUtil.toBean(jsonStr, new TypeReference<UserEmail>() {
        }, true);

        if (!email.equals(user.getEmail())){
            throw new RuntimeException("邮箱不匹配");
        }
        if (!code.equals(user.getCode())){
            throw new RuntimeException("验证码错误");
        }
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("email",email);
        User one = userMapper.selectOne(queryWrapper);
        if (one!= null) {
            UserDto userDto = new UserDto();
            BeanUtils.copyProperties(one, userDto);
            //设置token
            String token = TokenUtils.genToken(one.getId().toString(), one.getPassword());
            userDto.setToken(token);
            String roleName = one.getRole();
            //设置用户的菜单列表
            List<Menu> roleMenus = getRoleMenu(roleName);
            userDto.setMenus(roleMenus);

            return userDto;
        } else {
            throw new ServiceException(ResultCodeEnum.DATA_ERROR);
        }
    }

    /**
     * 获取当前角色的菜单列表
     * @param roleName
     * @return
     */
    private List<Menu> getRoleMenu(String roleName) {
        int roleId = roleMapper.getRoleId(roleName);
        //当前角色的所有菜id集合
        List<Integer> menuIds = roleMenuMapper.getMenuId(roleId);

        //查出系统所有的菜单
        List<Menu> menus = MenuService.getMenu("");
        //new一个最后筛选完成之后的list
        List<Menu> roleMenus = new ArrayList<>();
        //筛选当前用户角色的菜单
        for (Menu menu : menus) {
            if (menuIds.contains(menu.getId())) {
                roleMenus.add(menu);
            }
            List<Menu> children = menu.getChildren();
            //removeIf() 移除 children 里面不在 menuIds 集合中的元素
            boolean b = children.removeIf(child -> !menuIds.contains(child.getId()));
            if (children.size() != 0 && b) {
                roleMenus.add(menu);
            }
        }
        return roleMenus;
    }
}

